package com.bytebuddytest.classvisitor;

import com.alibaba.fastjson.JSON;
import com.util.ClassInfo;
import com.util.MethodInfo;
import com.util.ParamInfo;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.pool.TypePool;
import org.junit.Assert;
import org.junit.Test;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author yutianhong
 * @version 1.0
 * @since 2023/12/01 10:44
 */
public class TypePoolTest {

    private static final Map<String, ClassInfo> cache = new HashMap<>();

    @Test
    public void testTypeDescription() throws IOException {
        String jarPath = ClassLoader.getSystemClassLoader().getResource("").getPath();
        System.out.println("jarPath = " + jarPath);
        // 使用类加载器、指定路径创建 ClassFileLocator
        TypePool typePool = buildTypePool(jarPath);

        // 从 TypePool 获取类的 TypeDescription
        TypeDescription typeDescription = typePool.describe("com.asmtest.visitor.MyClass").resolve();

        // 现在可以获取类的元数据，比如方法、字段、注解等
        System.out.println("类全称：" + typeDescription.getTypeName());
        System.out.println("类简称：" + typeDescription.getLongSimpleName());
        System.out.println("类是不是接口：" + typeDescription.isInterface());
        System.out.println("类的注解：" + typeDescription.getDeclaredAnnotations());
        System.out.println("类的方法：" + typeDescription.getDeclaredMethods());
        System.out.println("类的字段：" + typeDescription.getDeclaredFields());
        System.out.println("类的第1个方法的返回值类型：" + typeDescription.getDeclaredMethods().get(0).getReturnType());
        System.out.println("类的第1个方法的第5个参数的注解：" + typeDescription.getDeclaredMethods().get(0).getParameters().get(5).getDeclaredAnnotations());
        System.out.println("类的第1个方法的第5个参数的第1个泛型的全称：" + typeDescription.getDeclaredMethods().get(0).getParameters().get(5).getType().getTypeArguments().get(0).getActualName());

        try {
            // classloader 不会加载类
            Method findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
            findLoadedClass.setAccessible(true);
            ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
            Object ret = findLoadedClass.invoke(systemClassLoader, "com.bytebuddytest.classcreation.Foo");
            Assert.assertNull(ret);
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @Test
    public void testScan() throws IOException {
        String jarPath = ClassLoader.getSystemClassLoader().getResource("").getPath();
        System.out.println("jarPath = " + jarPath);
        TypePool typePool = buildTypePool(jarPath);

        // 从 TypePool 获取类的 TypeDescription
        String className = "com.bytebuddytest.classvisitor.TestClass";
        Map<String, ClassInfo> classInfo = new ClassResolver(typePool).doResolve(className);
        System.out.println("class:");
        classInfo.keySet().forEach(System.out::println);
        System.out.println();
        System.out.println();
        System.out.println(JSON.toJSONString(classInfo, true));
    }

    @Test
    public void testTransferSchema() throws IOException {
        String jarPath = ClassLoader.getSystemClassLoader().getResource("").getPath();
        System.out.println("jarPath = " + jarPath);
        TypePool typePool = buildTypePool(jarPath);

        // 从 TypePool 获取类的 TypeDescription
        String className = "com.bytebuddytest.classvisitor.TestClass";
        Map<String, ClassInfo> classInfoMap = new ClassResolver(typePool).doResolve(className);
        Map<MethodInfo, Map<String, String>> stringMapMap = new ClassSchemaConverter(classInfoMap).convertToMethodSchema(className);
        for (Map.Entry<MethodInfo, Map<String, String>> entry : stringMapMap.entrySet()) {
            System.out.println("method: " + entry.getKey().methodName + " " + entry.getKey().inParam.stream().map(ParamInfo::getClassName).collect(Collectors.toList()));
            System.out.println("out: " + entry.getValue().get("out"));
            System.out.println("in: " + entry.getValue().get("in"));
            System.out.println();
        }
    }

    static TypePool buildTypePool(String jarPath) throws IOException {
        // 使用类加载器、指定路径创建 ClassFileLocator
        ClassFileLocator jarFileLocator = ClassFileLocator.ForJarFile.ofClassPath(jarPath);
//        // 只期望用bootstrap、ext的类加载器
//        ClassLoader parent = ClassLoader.getSystemClassLoader().getParent();
//        ClassFileLocator classLoaderLocator = ClassFileLocator.ForClassLoader.of(parent);
        ClassFileLocator classLoaderLocator = ClassFileLocator.ForClassLoader.of(ClassLoader.getSystemClassLoader());
        // 复合
        ClassFileLocator.Compound compoundLocator = new ClassFileLocator.Compound(jarFileLocator, classLoaderLocator);

        // 创建 TypePool 用于从 ClassFileLocator 解析类型
        return TypePool.Default.of(compoundLocator);
    }

}
